﻿using Castle.DynamicProxy;
using Microsoft.AspNetCore.Cors;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Framework.LinkTrackingLog.MyTest
{
    /// <summary>
    /// 方法监控服务实现
    /// </summary>
    public class MethodMonitoringService : IMethodMonitoringService
    {
        public IEnumerable<MethodMonitoringModel> GetMethodMonitorings()
        {
            return currBagModel.ToList();
        }

        /// <summary>
        /// 方法监控服务实现
        /// </summary>
        /// <param name="logAction">日志记录委托，默认为记录控制台日志</param>
        public MethodMonitoringService(Action<MethodMonitoringModel> logAction)
        {
            if (logAction != null) _logAction = logAction;
        }

        /// <summary>
        /// 父级信息
        /// </summary>
        private readonly AsyncLocal<MethodMonitoringModel> monitoringModel = new AsyncLocal<MethodMonitoringModel>();
        /// <summary>
        /// 结构树列表
        /// </summary>
        private readonly ConcurrentBag<MethodMonitoringModel> currBagModel = [];

        /// <summary>
        /// 日志记录委托，默认为控制台输出
        /// </summary>
        private static Action<MethodMonitoringModel> _logAction = (model) => {
            Console.WriteLine($"函数{model}为入口函数，执行完成，总耗时：{model.TotalTime}，总执行链路信息：{System.Text.Json.JsonSerializer.Serialize(model)}");
        };

        public IDisposable MonitoringService(string methodName, string className)
        {
            //初始化当前函数信息
            MethodMonitoringModel method = new MethodMonitoringModel
            {
                Name = methodName,//invocation.Method.Name,
                ClassName = className// invocation.TargetType.Name
            };
            //获取父级函数，作为备份
            var paraData = monitoringModel.Value;
            //父级为空，则为主入口函数
            if (paraData == null)
            {
                //添加结构树列表
                currBagModel.Add(method);
            }
            else
            {
                //父级函数不为空，则将当前函数添加到父级函数的子函数列表中
                paraData.ChildLevelModel.Add(method);
            }
            //将当前函数赋值给父级函数，便于在执行当前函数的子涵数时给当前函数添加子函数信息
            monitoringModel.Value = method;
            return new MethodMonitoringDisposable(() =>
            {
                //设置函数结束时间
                method.EndTime = DateTime.Now;
                //设置函数执行状态
                method.IsEnd = true;

                Console.WriteLine($"函数{monitoringModel.Value.Name}执行完成，执行耗时：{monitoringModel.Value.TotalTime}/ms");
                //当前函数执行完成时将父级函数恢复为父级节点
                monitoringModel.Value = paraData;
            });
        }

        /// <summary>
        /// 开始Action监控
        /// </summary>
        /// <param name="methodName">Action名称</param>
        /// <param name="className">控制器类名</param>
        public void StartMonitoring(string methodName,string className)
        {
            //当前方法只能在入口函数时使用
            if (monitoringModel?.Value != null) return;
            //初始化当前函数信息
            MethodMonitoringModel method = new MethodMonitoringModel()
            {
                Name = methodName,
                ClassName = className
            };
            currBagModel.Add(method);
        }

        /// <summary>
        /// 停止Action监控
        /// </summary>
        /// <param name="methodName">Action名称</param>
        /// <param name="className">控制器类名</param>
        public void StopMonitoring(string methodName, string className)
        {
            //当前方法只能在入口函数时使用
            if (monitoringModel?.Value == null) return;
            if (monitoringModel.Value.ClassName != className || monitoringModel.Value.Name != methodName) return;
            monitoringModel.Value.EndTime = DateTime.Now;
            monitoringModel.Value.IsEnd = true;
            _logAction(monitoringModel.Value);
        }

        /// <summary>
        /// 执行异常
        /// </summary>
        /// <param name="e"></param>
        public void Execute(Exception e)
        {
            if (monitoringModel?.Value == null) return;
            monitoringModel.Value.EndTime = DateTime.Now;
            monitoringModel.Value.IsEnd = true;
            monitoringModel.Value.Exception = e;
        }
    }

    /// <summary>
    /// 释放资源并执行委托
    /// </summary>
    public class MethodMonitoringDisposable : IDisposable
    {
        /// <summary>
        /// 函数执行结束前执行委托
        /// </summary>
        Action _action;
        /// <summary>
        /// 释放资源并执行委托
        /// </summary>
        /// <param name="action">释放资源时需要执行的委托</param>
        public MethodMonitoringDisposable(Action action)
        {
            _action = action;
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose() => _action();
    }
}
